package sqlite

import (
	"context"
	"database/sql"
	"encoding/json"
	"log"
	"time"
)

type ConfigModel struct {
	ID         string             `json:"id" bson:"id"`
	Namespace  string             `json:"ns" bson:"ns"` // Config 所属的 VMR namespace
	UpdatedAt  time.Time          `json:"updated_at" bson:"updated_at"`
	Ver        int64              `json:"ver" bson:"ver"`
	Info       interface{}        `json:"info" bson:"info"`
	CancelFunc context.CancelFunc `json:"-" bson:"-"` // for cancel
}

type SQLiteConfig struct {
	DBFile string
	db     *sql.DB
}

type IConfiger interface {
	// 设置 / 删除 / 查询
	Set(ctx context.Context, id, ns string, info interface{}) error
	Del(ctx context.Context, id, ns string) error
	Get(ctx context.Context, id, ns *string) ([]ConfigModel, error)
	// 检查配置更新
	Check(ctx context.Context, id, ns string, ver int64) (string, error)
}

var _ IConfiger = &SQLiteConfig{}

func Init(DBFile string) IConfiger {
	db, err := sql.Open("sqlite3", DBFile)
	if err != nil {
		log.Fatalf("open config db failed, err: %v", err)
	}

	//log.Info("init config table")

	sqlStmt := `CREATE TABLE IF NOT EXISTS config (
		id 			INTEGER PRIMARY KEY AUTOINCREMENT,
		ns			TEXT NOT NULL,
		info 		JSON NOT NULL,
		updated_at	DATETIME NOT NULL,
		ver			INTEGER DEFAULT 0
	);`
	_, err = db.Exec(sqlStmt)
	if err != nil {
		log.Fatalf("%q: %s", err, sqlStmt)
	}

	return &SQLiteConfig{
		DBFile: DBFile,
		db:     db,
	}
}

func (c SQLiteConfig) Set(ctx context.Context, id, ns string, info interface{}) error {
	stmt, err := c.db.PrepareContext(ctx, `INSERT INTO config(id, ns, info, updated_at, ver) VALUES(?, ?, ?, ?, ?) ON CONFLICT(id, ns) DO UPDATE SET info=excluded.info, ver=ver+1`)
	if err != nil {
		//log.Warnf("prepare err: %v", err)
		return err
	}
	defer stmt.Close()

	//infoStr := util.JsonStr(info)
	_, err = stmt.ExecContext(ctx, id, ns, "{}", time.Now(), 0)
	if err != nil {
		//log.Warnf("exec err: %v", err)
		return err
	}
	return nil
}

func (c SQLiteConfig) Get(ctx context.Context, id, ns *string) (configs []ConfigModel, err error) {
	stmt, err := c.db.PrepareContext(ctx, `SELECT id, info, updated_at, ver, ns FROM config WHERE id = ? AND ns = ?`)
	if err != nil {
		//log.Warnf("prepare query err: %v", err)
		return nil, err
	}
	defer stmt.Close()

	rows, err := stmt.QueryContext(ctx, *id, *ns)
	if err != nil {
		//log.Warnf("query err: %+v", err)
		return nil, err
	}
	for rows.Next() {
		var (
			config ConfigModel
			tmpStr string
		)
		err = rows.Scan(
			&config.ID,
			&tmpStr,
			&config.UpdatedAt,
			&config.Ver,
			&config.Namespace,
		)
		if err != nil {
			//log.Warnf("scan err: %v", err)
			continue
		}
		err = json.Unmarshal([]byte(tmpStr), &config.Info)
		if err != nil {
			//log.Warnf("convert json err: %v", err)
			continue
		}
		configs = append(configs, config)
	}

	return configs, nil
}

func (S SQLiteConfig) Del(ctx context.Context, id, ns string) error {
	panic("implement me")
}

func (S SQLiteConfig) Check(ctx context.Context, id, ns string, ver int64) (string, error) {
	panic("implement me")
}
